package 队列.循环队列;

import 队列.数组队列.Queue;

/*双端队列*/
public class TwoLoopQueue<E> implements TwoQueue<E> {

    private E []data;
    private int front;
    private int tail;
    private int size;

    public TwoLoopQueue(int capacity){
        data = (E[]) new Object[capacity];
        front = 0;
        tail = 0;
        size = 0;
    }
    public TwoLoopQueue(){
        this(10);
    }

    @Override
    public void addLast(E e) {
        if (isFull()){
            resize(2 * this.getCapacity());
        }
        data[tail] = e;
        tail = (tail+1) % data.length;
        size++;
    }

    @Override
    public void addFront(E e) {
        if (isFull()){
            resize(2 * this.getCapacity());
        }
        if (front != 0){
            data[--front] = e;
        }else {
            front = data.length - 1;
            data[front] = e;
        }
        size++;
    }

    @Override
    public E removeLast() {
        if (isEmpty()){
            throw new IllegalArgumentException("error");
        }
        if (tail != 0 ){
            tail = tail - 1;
        }else {
            tail = data.length - 1;
        }
        E res = data[tail];
        data[tail] = null;
        size--;
        return res;
    }

    @Override
    public E removeFront() {
        if (isEmpty()){
            throw new IllegalArgumentException("error");
        }
        E res = data[front];
        data[front] = null;
        front = (front+1) % data.length;
        size--;
        if (size == getCapacity()/ 4 && getCapacity() / 2 != 0){
            resize(getCapacity() / 2);
        }
        return res;
    }

    private void resize(int length) {
        E[] newData = (E[]) new Object[length];
        for (int i = 0; i < getSize(); i++) {
            newData[i] = data[(front+i) % data.length];
        }
        data = newData;
        front = 0;
        tail = size;

    }



    @Override
    public E getFront() {
        if (isEmpty()){
            throw new IllegalArgumentException("error");
        }
        return data[front];
    }

    @Override
    public E getLast() {
        if (isEmpty()){
            throw new IllegalArgumentException("error");
        }
        if (tail != 0 ){
            return data[tail-1];
        }else {
            return data[data.length - 1];
        }
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return getSize() == 0;
    }
    public int getCapacity(){
        return data.length;
    }
    public boolean isFull(){
        return getSize() == getCapacity();
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append(String.format("queue size = %d, capacity = %d\n", size, getCapacity()));
        builder.append("front [");
        for (int i = 0; i < size; i++) {
            builder.append(data[(i+front)%data.length]);
            if ((i + 1 +front) % data.length != tail){
                builder.append(",");
            }
        }
        builder.append("] tail");
        return builder.toString();
    }

    public static void main(String[] args) {
        TwoLoopQueue<Integer> classArray = new TwoLoopQueue<Integer>(10);
        for (int i = 1; i <= 10; i++) {
            if (i % 2 == 0)
                classArray.addFront(i);
            else
                classArray.addLast(i);
            System.out.println(classArray);
        }
        for (int i = 1; i <= 10; i++) {
            if (i % 2 == 0)
                classArray.removeLast();
            else
                classArray.removeFront();
            System.out.println(classArray);
        }

    }

}
